home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 43 / Mac Magazin and MacEasy Magazine CD - Issue 43.iso / Software / Entwickler / CCMArea / Source / UCMArea.cp < prev    next >
Encoding:
Text File  |  1998-02-12  |  7.8 KB  |  327 lines  |  [TEXT/CWIE]

  1. // CCMArea version 1.3
  2. // 11-11-97
  3. // by David Catmull
  4.  
  5. /* History:
  6.     
  7.     10-21-97        First version
  8.     
  9.     10-22-97        Added FindSuperCMArea
  10.     
  11.     11-11-97        Added sCmdStringID and delay click
  12.     
  13.     11-22-97        AdjustCursor returns false when CMM not present
  14.     
  15.     11-29-97        Added AppendMenuCommand
  16.     
  17.     12-2-97            Uncommented call to UCursor for PowerPlant 1.8
  18.     
  19.     12-9-97            AddCommandToMenu initializes enabled and usesMark to false
  20.     
  21.     2-10-98            Fixed clicks in title bars of windows behind modal dialogs
  22. */
  23.  
  24. #include "UCMArea.h"
  25. #include "CCMArea.h"
  26. #include <LCommander.h>
  27. #include <LMenuBar.h>
  28. #include <LMenu.h>
  29. #include <LPane.h>
  30.  
  31. #include <ContextualMenu.h>
  32. #include <Appearance.h>
  33.  
  34. Boolean UCMArea::sCMPresent = false,
  35.                 UCMArea::sDelayClick = false;
  36. ResIDT UCMArea::sCursorID = 999,
  37.              UCMArea::sCmdStringID = 999;
  38. CursHandle UCMArea::sCMCursor = 0L;
  39. long UCMArea::sDelay = 0;
  40.  
  41. const short modifierKeys = controlKey | optionKey | cmdKey | shiftKey | alphaLock;
  42. const ResIDT kCMCursorID = -20488;
  43.  
  44. /* ------------------------------------------------------------------------------------------------ */
  45. // Initialize
  46. //    Add the command with the given ID to the given menu
  47.  
  48. void
  49. UCMArea::Initialize()
  50. {
  51.     OSErr err;
  52.     long response;
  53.     
  54.     err = ::Gestalt(gestaltContextualMenuAttr,&response);
  55.     sCMPresent = (err == noErr) && (1 << gestaltContextualMenuPresent);
  56.     
  57.     if (sCMPresent) {
  58.         ::InitContextualMenus();
  59.         GetCMCursor();
  60.     }
  61. }
  62.  
  63. /* ------------------------------------------------------------------------------------------------ */
  64. // GetCMCursor
  65. //    Read in the CM cursor, checking for the Appearance cursor first
  66.  
  67. void
  68. UCMArea::GetCMCursor()
  69. {
  70.     if (sCMCursor)
  71.         ::ReleaseResource((Handle)sCMCursor);
  72.     
  73.     sCMCursor = ::GetCursor(kCMCursorID);
  74.     if (!sCMCursor)
  75.         sCMCursor = ::GetCursor(sCursorID);
  76. }
  77.  
  78. /* ------------------------------------------------------------------------------------------------ */
  79. // AddCommandToMenu
  80. //    Add the command with the given ID to the given menu
  81. //    Unless inOverrideDisable is true, disabled items are skipped
  82. //    Use this function to build menus more easily
  83.  
  84. Boolean
  85. UCMArea::AddCommandToMenu(MenuHandle inMenu,CommandT inCommand,Boolean inOverrideDisable)
  86. {
  87.     LMenuBar *menuBar = LMenuBar::GetCurrentMenuBar();
  88.     LMenu *menu = 0L;
  89.     
  90.     if (!inOverrideDisable) {
  91.         Boolean enabled = false,usesMark = false;
  92.         Char16 mark;
  93.         Str255 name;
  94.         
  95.         LCommander::GetTarget()->ProcessCommandStatus(inCommand,enabled,usesMark,mark,name);
  96.         if (!enabled)
  97.             return false;
  98.     }
  99.     
  100.     menuBar->FindNextMenu(menu);
  101.     
  102.     do {
  103.         short item;
  104.         
  105.         item = menu->IndexFromCommand(inCommand);
  106.         if (item > 0) {
  107.             MenuHandle menuH = menu->GetMacMenuH();
  108.             Str255 text;
  109.             
  110.             ::GetMenuItemText(menuH,item,text);
  111.             ::AppendMenu(inMenu,text);
  112.             ::SetMenuItemCommandID(inMenu,::CountMenuItems(inMenu),inCommand);
  113.             
  114.             return true;
  115.         }
  116.     } while (menuBar->FindNextMenu(menu));
  117.     
  118.     return false;
  119. }
  120.  
  121. /* ------------------------------------------------------------------------------------------------ */
  122. // AppendMenuCommand
  123. //    Append a menu item and set its command id
  124.  
  125. void
  126. UCMArea::AppendMenuCommand(MenuHandle inMenu,Str255 inItemText,CommandT inCommand)
  127. {
  128.     ::AppendMenu(inMenu,inItemText);
  129.     ::SetMenuItemCommandID(inMenu,::CountMenuItems(inMenu),inCommand);
  130. }
  131.  
  132. /* ------------------------------------------------------------------------------------------------ */
  133. // FindSuperCMArea
  134. //    Find the closest superView that is a CCMArea
  135.  
  136. void
  137. UCMArea::FindSuperCMArea(LPane *inPane,CCMArea *&outSuperCMArea,LView *&outSuperView)
  138. {
  139.     CCMArea *area;
  140.     LView *view;
  141.     
  142.     for (view = inPane->GetSuperView(); view; view = view->GetSuperView()) {
  143.         area = dynamic_cast<CCMArea*>(view);
  144.         if (area)
  145.             break;
  146.     }
  147.     
  148.     outSuperCMArea = area;
  149.     if (area)
  150.         outSuperView = view;
  151.     else
  152.         outSuperView = 0L;
  153. }
  154.  
  155. /* ------------------------------------------------------------------------------------------------ */
  156. // SetCMCursor
  157. //    Display the contextual menu cursor
  158.  
  159. void
  160. UCMArea::SetCMCursor()
  161. {
  162.     UCursor::SetTheCursor(sCursorID);
  163. }
  164.  
  165. /* ------------------------------------------------------------------------------------------------ */
  166. // WaitDelayClick
  167. //    Return true if the mouse stays down in the same place
  168. //    Like the opposite of WaitMouseMoved, only with a time limit
  169.  
  170. Boolean
  171. UCMArea::WaitDelayClick(const EventRecord &inEvent)
  172. {
  173.     long limit;
  174.     
  175.     if (!::StillDown())
  176.         return false;
  177.     
  178.     if (sDelay > 0)
  179.         limit = inEvent.when + sDelay;
  180.     else
  181.         limit = inEvent.when + GetDblTime();
  182.     
  183.     while (StillDown() && (TickCount() < limit)) {
  184.         Point mouse;
  185.         
  186.         GetMouse(&mouse);
  187.         ::LocalToGlobal(&mouse);
  188.         if (!::EqualPt(mouse,inEvent.where))
  189.             return false;
  190.     }
  191.     return ::StillDown();
  192. }
  193.  
  194. /* ------------------------------------------------------------------------------------------------ */
  195. // EventMouseDown
  196. //    Make sure contextual menus appear wherever appropriate
  197.  
  198. Boolean
  199. UCMArea::EventMouseDown(const EventRecord    &inMacEvent)
  200. {
  201.     WindowPtr    macWindowP;
  202.     Int16        thePart;
  203.     Boolean clickHandled = false;
  204.     SMouseDownEvent theMouseDown;
  205.     LWindow *windowObj;
  206.     CCMArea *area;
  207.     
  208.     if (!sCMPresent)
  209.         return false;
  210.     
  211.     thePart = ::FindWindow(inMacEvent.where, &macWindowP);
  212.     if (thePart == inMenuBar)
  213.         return false;
  214.     
  215.     if (!::IsShowContextualMenuClick(&inMacEvent)) {
  216.         if ((thePart == inContent) && sDelayClick) {
  217.             if (!WaitDelayClick(inMacEvent))
  218.                 return false;
  219.         }
  220.         else
  221.             return false;
  222.     }
  223.     
  224.     do {
  225.         windowObj = LWindow::FetchWindowObject(macWindowP);
  226.         if (!windowObj) break;
  227.         area = dynamic_cast<CCMArea*>(windowObj);
  228.         if (!area) break;
  229.         
  230.         theMouseDown.wherePort = inMacEvent.where;
  231.         windowObj->GlobalToPortPoint(theMouseDown.wherePort);
  232.         theMouseDown.whereLocal = theMouseDown.wherePort;
  233.         theMouseDown.macEvent = inMacEvent;
  234.         theMouseDown.delaySelect = false;
  235.         
  236.         switch (thePart) {
  237.         
  238.             case inDrag:
  239.             case inGrow:
  240.             case inGoAway:
  241.             case inZoomIn:
  242.             case inZoomOut:
  243.                 // Don't handle inactive windows when there's a modal dialog
  244.                 if (!UDesktop::WindowIsSelected(windowObj))
  245.                     if (!UDesktop::FrontWindowIsModal()) {
  246.                         UDesktop::SelectDeskWindow(windowObj);
  247.                         windowObj->Activate();
  248.                         windowObj->UpdatePort();
  249.                         area->CMClick(theMouseDown);
  250.                         clickHandled = true;
  251.                     }
  252.                 break;
  253.             
  254.             case inContent:
  255.                 do {
  256.                     LPane *hitPane;
  257.                     LView *superView;
  258.                     Point local = theMouseDown.wherePort;
  259.                     
  260.                     if (!UDesktop::FrontWindowIsModal()) {
  261.                         if (!UDesktop::WindowIsSelected(windowObj)) {
  262.                             UDesktop::SelectDeskWindow(windowObj);
  263.                             windowObj->Activate();
  264.                             windowObj->UpdatePort();
  265.                         }
  266.                     }
  267.                     else if (windowObj != UDesktop::FetchTopModal())
  268.                         break;
  269.                     
  270.                     hitPane = windowObj->FindDeepSubPaneContaining(local.h,local.v);
  271.                     if (!hitPane) hitPane = windowObj;
  272.                     
  273.                     if (hitPane->IsEnabled() && hitPane->IsActive() &&
  274.                             dynamic_cast<CCMArea*>(hitPane))
  275.                         break;    // Active CCMAreas can handle it themselves
  276.                     
  277.                     // Find the deepest owning superView that's a CCMArea
  278.                     // That could be the window
  279.                     
  280.                     FindSuperCMArea(hitPane,area,superView);
  281.                     
  282.                     if (!area) {
  283.                         area = dynamic_cast<CCMArea*>(windowObj);
  284.                         if (!area)
  285.                             break;
  286.                     }
  287.                     
  288.                     area->CMClick(theMouseDown);
  289.                     clickHandled = true;
  290.                 } while (false);
  291.         }
  292.     } while (false);
  293.     
  294.     return clickHandled;
  295. }
  296.  
  297. /* ------------------------------------------------------------------------------------------------ */
  298. // AdjustCursor
  299. //    Make sure the CM cursor appears where appropriate
  300.  
  301. Boolean
  302. UCMArea::AdjustCursor(const EventRecord &inMacEvent)
  303. {
  304.     WindowPtr windowPtr;
  305.     LWindow *windowObj;
  306.     
  307.     if (!sCMPresent)
  308.         return false;
  309.     
  310.     // Look for inactive CCMWindows
  311.     do {
  312.         if ((inMacEvent.modifiers & modifierKeys) != controlKey)    // Control key only
  313.             break;
  314.         
  315.         ::FindWindow(inMacEvent.where,&windowPtr);
  316.         if (!windowPtr) break;
  317.         windowObj = LWindow::FetchWindowObject(windowPtr);
  318.         if (!windowObj) break;
  319.         if (!dynamic_cast<CCMArea*>(windowObj)) break;
  320.         
  321.         UCMArea::SetCMCursor();
  322.         return true;
  323.     } while (false);
  324.     
  325.     return false;
  326. }
  327.